//
// Created by ych on 2/15/24.
//
#include "generator.h"

#define CODER_STRING_BUFFER_SIZE 64

void loadClib(Parser *parser) {
    parser->c_state.is_declare_func = True;
    for (int i = C_FUNC_SIZE - 1; i >= 0; i--) {
        insertFuncHashMap(&parser->symbols.func_table, CFuncInfos[i].func_name, CFuncInfos[i].func_params, 0,
                          parser->c_state.vm_i_f_p);
        codeKABx(&parser->c_state, OP_CALLC, K_NULL, CFuncInfos[i].cft, parser->c_state.vm_c_func_p);
        parser->y_state->memory.VM_C_FUNC[parser->c_state.vm_c_func_p++] = CFuncInfos[i].func_p;
        codeKABx(&parser->c_state, OP_MOVS, K_NULL, R3, 0);
        codeOPK(&parser->c_state, OP_LEV, K_NULL);
    }
    parser->c_state.is_declare_func = False;
}

static void codeOPK(CState *c_state, Uint opcode, Uint k) {
    if (c_state->is_declare_func) {
        c_state->memory->VM_I[c_state->vm_i_f_p++] = (k << OFFSET_K) | opcode;
    } else {
        c_state->memory->VM_I[c_state->vm_i_p++] = (k << OFFSET_K) | opcode;
    }
}

static void codeKABC(CState *c_state, Uint opcode, Uint k, Uint a, Uint b, Uint c) {
    if (c_state->is_declare_func) {
        c_state->memory->VM_I[c_state->vm_i_f_p++] =
                (c << OFFSET_C) | (b << OFFSET_B) | (a << OFFSET_A) | (k << OFFSET_K) | opcode;
    } else {
        c_state->memory->VM_I[c_state->vm_i_p++] =
                (c << OFFSET_C) | (b << OFFSET_B) | (a << OFFSET_A) | (k << OFFSET_K) | opcode;
    }
}

static void codeKABx(CState *c_state, Uint opcode, Uint k, Uint a, Uint bx) {
    if (c_state->is_declare_func) {
        c_state->memory->VM_I[c_state->vm_i_f_p++] = (bx << OFFSET_B) | (a << OFFSET_A) | (k << OFFSET_K) | opcode;
    } else {
        c_state->memory->VM_I[c_state->vm_i_p++] = (bx << OFFSET_B) | (a << OFFSET_A) | (k << OFFSET_K) | opcode;
    }
}

static void codeKBC(CState *c_state, Uint opcode, Uint k, Uint b, Uint c) {
    if (c_state->is_declare_func) {
        c_state->memory->VM_I[c_state->vm_i_f_p++] = (c << OFFSET_C) | (b << OFFSET_B) | (k << OFFSET_K) | opcode;
    } else {
        c_state->memory->VM_I[c_state->vm_i_p++] = (c << OFFSET_C) | (b << OFFSET_B) | (k << OFFSET_K) | opcode;
    }
}

static void throwCoder(Parser *parser, int code) {
    char buffer[CODER_STRING_BUFFER_SIZE];
    Error error;
    error.code = EXCEPTION_SEMILLEGAL;
    toStatementEnd(parser->lexer->reader);
    size_t start_pos = parser->lexer->reader->line_start_pos;
    cutString(&error.info, parser->lexer->reader->file_text.data, start_pos, parser->lexer->reader->pos - start_pos);
    sprintf(buffer, " line %zu:SEMANTIC ERROR", parser->lexer->reader->line);
    appendString(&error.info, buffer);
    //TODO THROW INFO CODER
    switch (code) {
        case SEM_MEM_OVERFLOW_ERROR:
            appendString(&error.info, " MEM OVERFLOW");
            break;
        case SEM_TYPE_ERROR:
            appendString(&error.info, " TYPE ERROR");
            break;
        case SEM_REDECLARE_VAR_ERROR:
            appendString(&error.info, " REDECLARE VAR");
            break;
        case SEM_UNDEFINED_VAR_ERROR:
            appendString(&error.info, " UNDEFINED VAR");
            break;
        case SEM_ARRAY_LENGTH_ERROR:
            appendString(&error.info, " EXCEEDING ARRAY LENGTH");
            break;
        case SEM_BREAK_NOT_IN_LOOP_STRUCT_ERROR:
            appendString(&error.info, " BREAK NOT IN LOOP STRUCT");
            break;
        case SEM_UNDEFINED_FUNCTION_ERROR:
            appendString(&error.info, " UNDEFINED FUNCTION");
            break;
        case SEM_FUNC_PARAM_ERROR:
            appendString(&error.info, " FUNC PARAM");
            break;
        case SEM_REDEFINED_FUNC_ERROR:
            appendString(&error.info, " REDEFINED FUNC");
            break;
        case SEM_FUNC_CAN_NOT_DEFINE_IN_FUNC :
            appendString(&error.info, " FUNC CAN NOT DEFINE IN FUNC");
            break;
        case SEM_RETURN_NOT_IN_FUNC:
            appendString(&error.info, " RETURN NOT IN FUNC");
            break;
    }
    pushErrorStack(&parser->y_state->errors, error);
}

static int findVar(VarHashMap *map, char *string, Uint *p) {
    VarHashNode *node;
    if (lookUpVarHashMap(map, string, &node)) {
        *p = node->value;
        return True;
    }
    return False;
}

static int findFunc(Parser *parser, char *string, FuncInfo *func_info) {
    FuncHashNode *node;
    if (lookUpFuncHashMap(&parser->symbols.func_table, string, &node)) {
        *func_info = node->value;
        return True;
    }
    return False;
}

static int allocVar(Parser *parser, VarHashMap *map, char *string, Uint *p) {
    if (parser->c_state.vm_mem_p >= YCH_VM_MEM_SIZE) {
        throwCoder(parser, SEM_MEM_OVERFLOW_ERROR);
        return False;
    } else {
        *p = parser->c_state.vm_mem_p++;
        insertVarHashMap(map, string, *p);
    }
    return True;
}

static int allocInnerVar(Parser *parser, VarHashMap *map, char *string, Uint *p) {
    insertVarHashMap(map, string, parser->c_state.func_mem_p);
    ++parser->func_info->var_nums;
    *p = parser->c_state.func_mem_p++;
    return True;
}

static Uint getIntConstP(Parser *parser, Int i) {
    IntHashNode *node;
    if (lookUpIntHashMap(&parser->symbols.int_table, i, &node)) {
        return node->value;
    }
    if (parser->c_state.vm_int_const_p >= YCH_VM_INT_CONST_SIZE) {
        throwCoder(parser, SEM_MEM_OVERFLOW_ERROR);
        throw(EXCEPTION_MEMORY);
    }
    insertIntHashMap(&parser->symbols.int_table, i, parser->c_state.vm_int_const_p);
    parser->y_state->memory.VM_INT_CONST[parser->c_state.vm_int_const_p] = i;
    return parser->c_state.vm_int_const_p++;
}

static Uint getFloatConstP(Parser *parser, Float f) {
    FloatHashNode *node;
    if (lookUpFloatHashMap(&parser->symbols.float_table, f, &node)) {
        return node->value;
    }
    if (parser->c_state.vm_float_const_p >= YCH_VM_FLOAT_CONST_SIZE) {
        throwCoder(parser, SEM_MEM_OVERFLOW_ERROR);
        throw(EXCEPTION_MEMORY);
    }
    insertFloatHashMap(&parser->symbols.float_table, f, parser->c_state.vm_float_const_p);
    parser->y_state->memory.VM_FLOAT_CONST[parser->c_state.vm_float_const_p] = f;
    return parser->c_state.vm_float_const_p++;
}

static Uint getStringConstP(Parser *parser, char *string) {
    StringHashNode *node;
    if (lookUpStringHashMap(&parser->symbols.string_table, string, &node)) {
        return node->value;
    }
    if (parser->c_state.vm_string_const_p >= YCH_VM_STRING_CONST_SIZE) {
        throwCoder(parser, SEM_MEM_OVERFLOW_ERROR);
        throw(EXCEPTION_MEMORY);
    }
    insertStringHashMap(&parser->symbols.string_table, string, parser->c_state.vm_string_const_p);
    copyString(&parser->y_state->memory.VM_STR_CONST[parser->c_state.vm_string_const_p], string);
    return parser->c_state.vm_string_const_p++;
}


static void genCodeByMInfo(Parser *parser, MInfo m, Uint R) {
    switch (m.type) {
        case MT_VAR:
            codeKABx(&parser->c_state, OP_LOAD, K_NULL, R, m.value.p);
            break;
        case MT_T:
        case MT_MAT_V:
            codeKABx(&parser->c_state, OP_MOVS, K_NULL, R, 0);
            break;
        case MT_INT_CONST:
            codeKABx(&parser->c_state, OP_LOAD_CONST, LOAD_CONST_INT, R, getIntConstP(parser, m.value.i));
            break;
        case MT_FLOAT_CONST:
            codeKABx(&parser->c_state, OP_LOAD_CONST, LOAD_CONST_FLOAT, R, getFloatConstP(parser, m.value.f));
            break;
        case MT_BOOL_CONST:
            codeKABx(&parser->c_state, OP_LOAD_CONST, LOAD_CONST_BOOL, R, m.value.b);
            break;
        case MT_STRING_CONST:
            codeKABx(&parser->c_state, OP_LOAD_CONST, LOAD_CONST_STRING, R,
                     m.value.p);
            break;
        case MT_OBJ_P:
            codeKABx(&parser->c_state, OP_LOAD_P, K_NULL, R, 0);
            break;
        default:
            throwCoder(parser, SEM_ERROR);
            throw(EXCEPTION_SEMILLEGAL);
    }
}

int ac(Parser *parser, T ac) {
    switch (ac) {
        case AC_PUSH_CONST:
            return acPushConst(parser);
        case AC_STAGE:
            return acStage(parser);
        case AC_MALLOC_VAR:
            return acMallocVar(parser);
        case AC_ASSIGN_FIRST:
            return acAssignFirst(parser);
        case AC_SEM_POP:
            return acSemPop(parser);
        case AC_POP:
            return acPop(parser);
        case AC_PUSH_VAR:
            return acPushVar(parser);
        case AC_PUSH_FUNC:
            return acPushFunc(parser);
        case AC_ADD:
            return acCompute(parser, OP_ADD, False);
        case AC_SUB:
            return acCompute(parser, OP_SUB, False);
        case AC_MUL:
            return acCompute(parser, OP_MUL, False);
        case AC_DIV:
            return acCompute(parser, OP_DIV, False);
        case AC_INNER:
            return acInner(parser);
        case AC_MOD:
            return acCompute(parser, OP_MOD, False);
        case AC_POW:
            return acCompute(parser, OP_POW, False);
        case AC_LESS:
            return acCompute(parser, OP_LESS, False);
        case AC_GREATER:
            return acCompute(parser, OP_LESS, True);
        case AC_LESSEQUAL:
            return acCompute(parser, OP_LESSEQUAL, False);
        case AC_GREATEREQUAL:
            return acCompute(parser, OP_LESSEQUAL, True);
        case AC_EQUAL:
            return acCompute(parser, OP_EQUAL, False);
        case AC_NOTEQUAL:
            return acCompute(parser, OP_NOTEQUAL, False);
        case AC_NEG:
            return acNeg(parser);
        case AC_AND:
            return acCompute(parser, OP_AND, False);
        case AC_OR:
            return acCompute(parser, OP_OR, False);
        case AC_NOT:
            return acNot(parser);
        case AC_ASSIGN_END:
            return acAssignEnd(parser);
        case AC_SEM_PUSH_ASSIGN:
            return acSemPushAssign(parser);
        case AC_FUNC_COUNT_PARAM:
            return acFuncCount(parser);
        case AC_FUNC_END:
            return acFuncEnd(parser);
        case AC_IF_JUDGE:
            return acIfJudge(parser);
        case AC_WHILE_JUDGE:
            return acWhileJudge(parser);
        case AC_SEM_PUSH_WHILE:
            return acSemPushWhile(parser);
        case AC_WHILE_END:
            return acWhileEnd(parser);
        case AC_WHILE_BREAK:
            return acWhileBreak(parser);
        case AC_IF_END:
            return acIfEnd(parser);
        case AC_SEM_PUSH_ELSE:
            return acSemPushElse(parser);
        case AC_ELSE_END:
            return acElseEnd(parser);
        case AC_DEF_FUNC_START:
            return acDefFuncStart(parser);
        case AC_DEF_COUNT_PARAMS:
            return acDefCountParams(parser);
        case AC_RETURN:
            return acReturn(parser);
        case AC_DEF_FUNC_END:
            return acDefFuncEnd(parser);
        case AC_MAT_COUNT_ROW:
            return acMatCountRow(parser);
        case AC_MAT_COUNT_COL:
            return acMatCountCol(parser);
        case AC_MAT_START:
            return acMatStart(parser);
        case AC_MAT_END:
            return acMatEnd(parser);
        case AC_INDEX:
            return acIndex(parser);
        case AC_MAT_INDEX:
            return acMatIndex(parser);
        case AC_ARRAY_START:
            return acArrayStart(parser);
        case AC_ARRAY_VALUE_ASSIGN:
            return acArrayValueAssign(parser);
        case AC_ARRAY_END:
            return acArrayEnd(parser);
        case AC_SET_ARRAY_LENGTH:
            return acSetArrayLength(parser);
        default:
            printf("AC dont realized\n");
    }
    return SEM_ERROR;
}

static int acStage(Parser *parser) {
    parser->temp_string = strdup(parser->current_token.token_value.string->data);
    return SEM_OK;
}

static int acMallocVar(Parser *parser) {
    MInfo item;
    Uint p;
    if (parser->c_state.is_declare_func) {
        if (findVar(&parser->symbols.inner_var_table, parser->current_token.token_value.string->data, &p)) {
            throwCoder(parser, SEM_REDECLARE_VAR_ERROR);
            return SEM_REDECLARE_VAR_ERROR;
        }
        allocInnerVar(parser, &parser->symbols.inner_var_table, parser->current_token.token_value.string->data, &p);
    } else {
        if (findVar(&parser->symbols.var_table, parser->current_token.token_value.string->data, &p)) {
            throwCoder(parser, SEM_REDECLARE_VAR_ERROR);
            return SEM_REDECLARE_VAR_ERROR;
        }
        allocVar(parser, &parser->symbols.var_table, parser->current_token.token_value.string->data, &p);
        if (parser->lexer->y_state->mode == YSTATE_INTERACTIVE) {
            stageVar(parser);
        }
    }
    item.type = MT_VAR;
    item.value.p = p;
    pushSEMStack(&parser->sem_stack, item);
    return SEM_OK;
}

static int acAssignFirst(Parser *parser) {
    MInfo m2 = popSEMStack(&parser->sem_stack), m1 = popSEMStack(&parser->sem_stack);
    genCodeByMInfo(parser, m2, R1);
    codeKABx(&parser->c_state, OP_STORE, K_NULL, R1, m1.value.p);
    return SEM_OK;
}

static int acAssignEnd(Parser *parser) {
    SEMStack *sem_stack = &parser->sem_stack;
    while (sem_stack->array[sem_stack->top - 1].type == MT_ASSIGN) {
        MInfo m2 = popSEMStack(sem_stack);
        popSEMStack(sem_stack);
        MInfo m1 = topSEMStack(sem_stack);
        if (m1.type == MT_VAR) {
            genCodeByMInfo(parser, m2, R1);
            codeKABx(&parser->c_state, OP_STORE, K_NULL, R1, m1.value.p);
        } else if (m1.type == MT_MAT_V) {
            genCodeByMInfo(parser, m2, R1);
            codeKABx(&parser->c_state, OP_MAT_ASSIGN, K_NULL, R1, 0);
        } else if (m1.type == MT_OBJ_P) {
            genCodeByMInfo(parser, m2, R1);
            codeKABx(&parser->c_state, OP_ASSIGN_P, K_NULL, R1, 0);
        } else {
            throwCoder(parser, SEM_ERROR);
            return SEM_ERROR;
        }
    }
    return SEM_OK;
}

static int acSemPushAssign(Parser *parser) {
    MInfo item;
    item.type = MT_ASSIGN;
    pushSEMStack(&parser->sem_stack, item);
    return SEM_OK;
}

static int acSemPop(Parser *parser) {
    if (parser->c_state.is_declare_func) {
        codeKABx(&parser->c_state, OP_PUSH, K_NULL, R7, 0);
    }
    popSEMStack(&parser->sem_stack);
    return SEM_OK;
}

static int acPop(Parser *parser) {
    MInfo item = topSEMStack(&parser->sem_stack);
    if (item.type == MT_T || item.type == MT_MAT_V || item.type == MT_OBJ_P)
        codeOPK(&parser->c_state, OP_POP, K_NULL);
    popSEMStack(&parser->sem_stack);
    return SEM_OK;
}

static int acPushConst(Parser *parser) {
    SEMStack *stack = &parser->sem_stack;
    Token *token = &parser->current_token;
    MInfo item;
    switch (token->token_type) {
        case TK_INT_V:
            item.type = MT_INT_CONST, item.value.i = token->token_value.i;
            break;
        case TK_FLOAT_V:
            item.type = MT_FLOAT_CONST, item.value.f = token->token_value.f;
            break;
        case TK_TRUE:
            item.type = MT_BOOL_CONST, item.value.b = True;
            break;
        case TK_FALSE:
            item.type = MT_BOOL_CONST, item.value.b = False;
            break;
        case TK_STRING_V://TODO PUSH CONST TK_STRING_V
            item.type = MT_STRING_CONST, item.value.p = getStringConstP(parser, token->token_value.string->data);
            break;
        default:
            return SEM_ERROR;
    }
    pushSEMStack(stack, item);
    return SEM_OK;
}

static int acPushFunc(Parser *parser) {
    FuncInfo func_info;
    if (!findFunc(parser, parser->temp_string, &func_info)) {
        free(parser->temp_string);
        throwCoder(parser, SEM_UNDEFINED_FUNCTION_ERROR);
        return SEM_UNDEFINED_FUNCTION_ERROR;
    }
    MInfo item;
    item.type = MT_T;
    pushSEMStack(&parser->sem_stack, item);
    FuncState *pre = parser->func_state;
    parser->func_state = malloc(sizeof(FuncState));
    parser->func_state->pre = pre;
    parser->func_state->func_params = func_info.func_params;
    parser->func_state->count = func_info.func_params;
    parser->func_state->var_nums = func_info.var_nums;
    parser->func_state->func_p = func_info.func_p;
    free(parser->temp_string);
    return SEM_OK;
}

static int acFuncCount(Parser *parser) {
    if (!parser->func_state->count--) {
        throwCoder(parser, SEM_FUNC_PARAM_ERROR);
        return SEM_FUNC_PARAM_ERROR;
    }
    MInfo item = popSEMStack(&parser->sem_stack);
    if (item.type != MT_T && item.type != MT_MAT_V) {
        genCodeByMInfo(parser, item, R1);
        codeKABx(&parser->c_state, OP_PUSHP, K_NULL, R1, 0);
    }
    return SEM_OK;
}

static int acFuncEnd(Parser *parser) {
    FuncState *temp = parser->func_state;
    if (temp->count) {
        throwCoder(parser, SEM_FUNC_PARAM_ERROR);
        return SEM_FUNC_PARAM_ERROR;
    }
    for (int i = temp->var_nums; i > 0; i--) {
        codeKABx(&parser->c_state, OP_PUSH, K_NULL, R7, 0);
    }
    codeKABx(&parser->c_state, OP_CALL, K_NULL, temp->func_params + temp->var_nums, temp->func_p - 1);
    for (int i = temp->var_nums + temp->func_params; i > 0; i--) {
        codeOPK(&parser->c_state, OP_POPP, K_NULL);
    }
    codeKABx(&parser->c_state, OP_PUSH, K_NULL, R3, 0);
    parser->func_state = temp->pre;
    free(temp);
    return SEM_OK;
}


static int acPushVar(Parser *parser) {
    Uint p;
    if (!findVar(parser->c_state.is_declare_func ? &parser->symbols.inner_var_table : &parser->symbols.var_table,
                 parser->temp_string, &p)) {
        free(parser->temp_string);
        throwCoder(parser, SEM_UNDEFINED_VAR_ERROR);
        return SEM_UNDEFINED_VAR_ERROR;
    }
    MInfo item;
    item.type = MT_VAR, item.value.p = p;
    pushSEMStack(&parser->sem_stack, item);
    free(parser->temp_string);
    return SEM_OK;
}


static int acCompute(Parser *parser, Uint OPCODE, int isInterchange) {
    MInfo m2 = popSEMStack(&parser->sem_stack);
    MInfo m1 = popSEMStack(&parser->sem_stack);
    CState *c_state = &parser->c_state;
    MInfo item;
    if (isInterchange) {
        MInfo temp = m2;
        m2 = m1, m1 = temp;
    }
    item.type = MT_T;
    switch (m1.type) {
        case MT_VAR:
            codeKABx(c_state, OP_LOAD, K_NULL, R0, m1.value.p);
            genCodeByMInfo(parser, m2, R1);
            codeOPK(c_state, OPCODE, K_NULL);
            break;
        case MT_T:
        case MT_MAT_V:
            codeKABx(c_state, OP_MOVS, K_NULL, R0, 0);
            genCodeByMInfo(parser, m2, R1);
            codeOPK(c_state, OPCODE, K_NULL);
            break;
        case MT_OBJ_P:
            codeKABx(&parser->c_state, OP_LOAD_P, K_NULL, R0, 0);
            genCodeByMInfo(parser, m2, R1);
            codeOPK(c_state, OPCODE, K_NULL);
            break;
        case MT_INT_CONST:
            switch (m2.type) {
                case MT_VAR:
                    codeKABx(c_state, OP_LOAD_CONST, LOAD_CONST_INT, R0, getIntConstP(parser, m1.value.i));
                    codeKABx(c_state, OP_LOAD, K_NULL, R1, m2.value.p);
                    codeOPK(c_state, OPCODE, K_NULL);
                    break;
                case MT_T:
                case MT_MAT_V:
                    codeKABx(c_state, OP_LOAD_CONST, LOAD_CONST_INT, R0, getIntConstP(parser, m1.value.i));
                    codeKABx(c_state, OP_MOVS, K_NULL, R1, 0);
                    codeOPK(c_state, OPCODE, K_NULL);
                    break;
                case MT_OBJ_P:
                    codeKABx(c_state, OP_LOAD_CONST, LOAD_CONST_INT, R0, getIntConstP(parser, m1.value.i));
                    codeKABx(&parser->c_state, OP_LOAD_P, K_NULL, R1, 0);
                    codeOPK(c_state, OPCODE, K_NULL);
                    break;
                case MT_INT_CONST:
                    item.type = MT_INT_CONST;
                    switch (OPCODE) {
                        case OP_ADD:
                            item.value.i = m1.value.i + m2.value.i;
                            break;
                        case OP_SUB:
                            item.value.i = m1.value.i - m2.value.i;
                            break;
                        case OP_MUL:
                            item.value.i = m1.value.i * m2.value.i;
                            break;
                        case OP_DIV:
                            item.value.i = m1.value.i / m2.value.i;
                            break;
                        case OP_MOD:
                            item.value.i = m1.value.i % m2.value.i;
                            break;
                        case OP_POW:
                            item.value.i = pow(m1.value.i, m2.value.i);
                            break;
                        case OP_LESS:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i < m2.value.i;
                            break;
                        case OP_LESSEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i <= m2.value.i;
                            break;
                        case OP_EQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i == m2.value.i;
                            break;
                        case OP_NOTEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i != m2.value.i;
                            break;
                        case OP_AND:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i & m2.value.i;
                            break;
                        case OP_OR:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i | m2.value.i;
                            break;
                        default:
                            throwCoder(parser, SEM_TYPE_ERROR);
                            return SEM_TYPE_ERROR;
                    }
                    break;
                case MT_FLOAT_CONST:
                    item.type = MT_FLOAT_CONST;
                    switch (OPCODE) {
                        case OP_ADD:
                            item.value.f = m1.value.i + m2.value.f;
                            break;
                        case OP_SUB:
                            item.value.f = m1.value.i - m2.value.f;
                            break;
                        case OP_MUL:
                            item.value.f = m1.value.i * m2.value.f;
                            break;
                        case OP_DIV:
                            item.value.f = m1.value.i / m2.value.f;
                            break;
                        case OP_POW:
                            item.value.f = pow(m1.value.i, m2.value.f);
                            break;
                        case OP_LESS:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i < m2.value.f;
                            break;
                        case OP_LESSEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i <= m2.value.f;
                            break;
                        case OP_EQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i == m2.value.f;
                            break;
                        case OP_NOTEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i != m2.value.f;
                            break;
                        default:
                            throwCoder(parser, SEM_TYPE_ERROR);
                            return SEM_TYPE_ERROR;
                    }
                    break;
                case MT_BOOL_CONST:
                    item.type = MT_INT_CONST;
                    switch (OPCODE) {
                        case OP_ADD:
                            item.value.i = m1.value.i + m2.value.b;
                            break;
                        case OP_SUB:
                            item.value.i = m1.value.i - m2.value.b;
                            break;
                        case OP_MUL:
                            item.value.i = m1.value.i * m2.value.b;
                            break;
                        case OP_DIV:
                            item.value.i = m1.value.i / m2.value.b;
                            break;
                        case OP_MOD:
                            item.value.i = m1.value.i % m2.value.b;
                            break;
                        case OP_POW:
                            item.value.i = pow(m1.value.i, m2.value.b);
                            break;
                        case OP_LESS:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i < m2.value.b;
                            break;
                        case OP_LESSEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i <= m2.value.b;
                            break;
                        case OP_EQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i == m2.value.b;
                            break;
                        case OP_NOTEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i != m2.value.b;
                            break;
                        case OP_AND:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i & m2.value.b;
                            break;
                        case OP_OR:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.i | m2.value.b;
                            break;
                        default:
                            throwCoder(parser, SEM_TYPE_ERROR);
                            return SEM_TYPE_ERROR;
                    }
                    break;
                default:
                    throwCoder(parser, SEM_TYPE_ERROR);
                    return SEM_TYPE_ERROR;
            }
            break;
        case MT_FLOAT_CONST:
            switch (m2.type) {
                case MT_VAR:
                    codeKABx(c_state, OP_LOAD_CONST, LOAD_CONST_FLOAT, R0, getFloatConstP(parser, m1.value.f));
                    codeKABx(c_state, OP_LOAD, K_NULL, R1, m2.value.p);
                    codeOPK(c_state, OPCODE, K_NULL);
                    break;
                case MT_T:
                case MT_MAT_V:
                    codeKABx(c_state, OP_LOAD_CONST, LOAD_CONST_FLOAT, R0, getFloatConstP(parser, m1.value.f));
                    codeKABx(c_state, OP_MOVS, K_NULL, R1, 0);
                    codeOPK(c_state, OPCODE, K_NULL);
                    break;
                case MT_OBJ_P:
                    codeKABx(c_state, OP_LOAD_CONST, LOAD_CONST_FLOAT, R0, getFloatConstP(parser, m1.value.f));
                    codeKABx(&parser->c_state, OP_LOAD_P, K_NULL, R1, 0);
                    codeOPK(c_state, OPCODE, K_NULL);
                    break;
                case MT_INT_CONST:
                    item.type = MT_FLOAT_CONST;
                    switch (OPCODE) {
                        case OP_ADD:
                            item.value.f = m1.value.f + m2.value.i;
                            break;
                        case OP_SUB:
                            item.value.f = m1.value.f - m2.value.i;
                            break;
                        case OP_MUL:
                            item.value.f = m1.value.f * m2.value.i;
                            break;
                        case OP_DIV:
                            item.value.f = m1.value.f / m2.value.i;
                            break;
                        case OP_POW:
                            item.value.i = pow(m1.value.f, m2.value.i);
                            break;
                        case OP_LESS:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f < m2.value.i;
                            break;
                        case OP_LESSEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f <= m2.value.i;
                            break;
                        case OP_EQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f == m2.value.i;
                            break;
                        case OP_NOTEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f != m2.value.i;
                            break;
                        default:
                            throwCoder(parser, SEM_TYPE_ERROR);
                            return SEM_TYPE_ERROR;
                    }
                    break;
                case MT_FLOAT_CONST:
                    item.type = MT_FLOAT_CONST;
                    switch (OPCODE) {
                        case OP_ADD:
                            item.value.f = m1.value.f + m2.value.f;
                            break;
                        case OP_SUB:
                            item.value.f = m1.value.f - m2.value.f;
                            break;
                        case OP_MUL:
                            item.value.f = m1.value.f * m2.value.f;
                            break;
                        case OP_DIV:
                            item.value.f = m1.value.f / m2.value.f;
                            break;
                        case OP_POW:
                            item.value.f = pow(m1.value.f, m2.value.f);
                            break;
                        case OP_LESS:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f < m2.value.f;
                            break;
                        case OP_LESSEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f <= m2.value.f;
                            break;
                        case OP_EQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f == m2.value.f;
                            break;
                        case OP_NOTEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f != m2.value.f;
                            break;
                        default:
                            throwCoder(parser, SEM_TYPE_ERROR);
                            return SEM_TYPE_ERROR;
                    }
                    break;
                case MT_BOOL_CONST:
                    item.type = MT_FLOAT_CONST;
                    switch (OPCODE) {
                        case OP_ADD:
                            item.value.f = m1.value.f + m2.value.b;
                            break;
                        case OP_SUB:
                            item.value.f = m1.value.f - m2.value.b;
                            break;
                        case OP_MUL:
                            item.value.f = m1.value.f * m2.value.b;
                            break;
                        case OP_DIV:
                            item.value.f = m1.value.f / m2.value.b;
                            break;
                        case OP_POW:
                            item.value.i = pow(m1.value.f, m2.value.b);
                            break;
                        case OP_LESS:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f < m2.value.b;
                            break;
                        case OP_LESSEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f <= m2.value.b;
                            break;
                        case OP_EQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f == m2.value.b;
                            break;
                        case OP_NOTEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.f != m2.value.b;
                            break;
                        default:
                            throwCoder(parser, SEM_TYPE_ERROR);
                            return SEM_TYPE_ERROR;
                    }
                    break;
                default:
                    throwCoder(parser, SEM_TYPE_ERROR);
                    return SEM_TYPE_ERROR;
            }
            break;
        case MT_BOOL_CONST:
            switch (m2.type) {
                case MT_VAR:
                    codeKABx(c_state, OP_LOAD_CONST, LOAD_CONST_BOOL, R0, m1.value.b);
                    codeKABx(c_state, OP_LOAD, K_NULL, R1, m2.value.p);
                    codeOPK(c_state, OPCODE, K_NULL);
                    break;
                case MT_T:
                case MT_MAT_V:
                    codeKABx(c_state, OP_LOAD_CONST, LOAD_CONST_BOOL, R0, m1.value.b);
                    codeKABx(c_state, OP_MOVS, K_NULL, R1, 0);
                    codeOPK(c_state, OPCODE, K_NULL);
                    break;
                case MT_OBJ_P:
                    codeKABx(c_state, OP_LOAD_CONST, LOAD_CONST_BOOL, R0, m1.value.b);
                    codeKABx(&parser->c_state, OP_LOAD_P, K_NULL, R1, 0);
                    codeOPK(c_state, OPCODE, K_NULL);
                    break;
                case MT_INT_CONST:
                    item.type = MT_INT_CONST;
                    switch (OPCODE) {
                        case OP_ADD:
                            item.value.i = m1.value.b + m2.value.i;
                            break;
                        case OP_SUB:
                            item.value.i = m1.value.b - m2.value.i;
                            break;
                        case OP_MUL:
                            item.value.i = m1.value.b * m2.value.i;
                            break;
                        case OP_DIV:
                            item.value.i = m1.value.b / m2.value.i;
                            break;
                        case OP_MOD:
                            item.value.i = m1.value.b % m2.value.i;
                            break;
                        case OP_POW:
                            item.value.i = pow(m1.value.b, m2.value.i);
                            break;
                        case OP_LESS:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.b < m2.value.i;
                            break;
                        case OP_LESSEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.b <= m2.value.i;
                            break;
                        case OP_EQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.b == m2.value.i;
                            break;
                        case OP_NOTEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.b != m2.value.i;
                            break;
                        case OP_AND:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.b & m2.value.i;
                            break;
                        case OP_OR:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.b | m2.value.i;
                            break;
                        default:
                            throwCoder(parser, SEM_TYPE_ERROR);
                            return SEM_TYPE_ERROR;
                    }
                    break;
                case MT_FLOAT_CONST:
                    item.type = MT_FLOAT_CONST;
                    switch (OPCODE) {
                        case OP_ADD:
                            item.value.f = m1.value.b + m2.value.f;
                            break;
                        case OP_SUB:
                            item.value.f = m1.value.b - m2.value.f;
                            break;
                        case OP_MUL:
                            item.value.f = m1.value.b * m2.value.f;
                            break;
                        case OP_DIV:
                            item.value.f = m1.value.b / m2.value.f;
                            break;
                        case OP_POW:
                            item.value.f = pow(m1.value.b, m2.value.f);
                            break;
                        case OP_LESS:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.b < m2.value.f;
                            break;
                        case OP_LESSEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.b <= m2.value.f;
                            break;
                        case OP_EQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.b == m2.value.f;
                            break;
                        case OP_NOTEQUAL:
                            item.type = MT_BOOL_CONST;
                            item.value.b = m1.value.b != m2.value.f;
                            break;
                        default:
                            throwCoder(parser, SEM_TYPE_ERROR);
                            return SEM_TYPE_ERROR;
                    }
                    break;
                case MT_BOOL_CONST:
                    item.type = MT_BOOL_CONST;
                    switch (OPCODE) {
                        case OP_ADD:
                            item.value.i = m1.value.b + m2.value.b;
                            break;
                        case OP_SUB:
                            item.value.i = m1.value.b - m2.value.b;
                            break;
                        case OP_MUL:
                            item.value.i = m1.value.b * m2.value.b;
                            break;
                        case OP_DIV:
                            item.value.i = m1.value.b / m2.value.b;
                            break;
                        case OP_MOD:
                            item.value.i = m1.value.b % m2.value.b;
                            break;
                        case OP_POW:
                            item.value.i = pow(m1.value.b, m2.value.b);
                            break;
                        case OP_LESS:
                            item.value.b = m1.value.b < m2.value.b;
                            break;
                        case OP_LESSEQUAL:
                            item.value.b = m1.value.b <= m2.value.b;
                            break;
                        case OP_EQUAL:
                            item.value.b = m1.value.b == m2.value.b;
                            break;
                        case OP_NOTEQUAL:
                            item.value.b = m1.value.b != m2.value.b;
                            break;
                        case OP_AND:
                            item.value.b = m1.value.b & m2.value.b;
                            break;
                        case OP_OR:
                            item.value.b = m1.value.b | m2.value.b;
                            break;
                        default:
                            throwCoder(parser, SEM_TYPE_ERROR);
                            return SEM_TYPE_ERROR;
                    }
                    break;
                default:
                    throwCoder(parser, SEM_TYPE_ERROR);
                    return SEM_TYPE_ERROR;
            }
            break;
        default:
            throwCoder(parser, SEM_TYPE_ERROR);
            return SEM_TYPE_ERROR;
    }
    pushSEMStack(&parser->sem_stack, item);
    return SEM_OK;
}

static int acNeg(Parser *parser) {
    MInfo item = popSEMStack(&parser->sem_stack);
    switch (item.type) {
        case MT_VAR:
            item.type = MT_T;
            codeKABx(&parser->c_state, OP_LOAD, K_NULL, R0, item.value.p);
            codeOPK(&parser->c_state, OP_NEG, K_NULL);
            break;
        case MT_T:
        case MT_MAT_V:
            item.type = MT_T;
            codeKABx(&parser->c_state, OP_MOVS, K_NULL, R0, 0);
            codeOPK(&parser->c_state, OP_NEG, K_NULL);
            break;
        case MT_OBJ_P:
            item.type = MT_T;
            codeKABx(&parser->c_state, OP_LOAD_P, K_NULL, R0, 0);
            codeOPK(&parser->c_state, OP_NEG, K_NULL);
            break;
        case MT_INT_CONST:
            item.value.i = -item.value.i;
            break;
        case MT_FLOAT_CONST:
            item.value.f = -item.value.f;
            break;
        case MT_BOOL_CONST:
            item.value.b = -item.value.b;
            break;
        default:
            throwCoder(parser, SEM_TYPE_ERROR);
            return SEM_TYPE_ERROR;
    }
    pushSEMStack(&parser->sem_stack, item);
    return SEM_OK;
}

static int acNot(Parser *parser) {
    MInfo item = popSEMStack(&parser->sem_stack);
    switch (item.type) {
        case MT_VAR:
            item.type = MT_T;
            codeKABx(&parser->c_state, OP_LOAD, K_NULL, R0, item.value.p);
            codeOPK(&parser->c_state, OP_NOT, K_NULL);
            break;
        case MT_T:
        case MT_MAT_V:
            item.type = MT_T;
            codeKABx(&parser->c_state, OP_MOVS, K_NULL, R0, 0);
            codeOPK(&parser->c_state, OP_NOT, K_NULL);
            break;
        case MT_OBJ_P:
            item.type = MT_T;
            codeKABx(&parser->c_state, OP_LOAD_P, K_NULL, R0, 0);
            codeOPK(&parser->c_state, OP_NOT, K_NULL);
            break;
        case MT_INT_CONST:
            item.value.i = !item.value.i;
            break;
        case MT_BOOL_CONST:
            item.value.b = !item.value.b;
            break;
        default:
            throwCoder(parser, SEM_TYPE_ERROR);
            return SEM_TYPE_ERROR;
    }
    pushSEMStack(&parser->sem_stack, item);
    return SEM_OK;
}

static int acInner(Parser *parser) {
    MInfo m2 = popSEMStack(&parser->sem_stack), m1 = popSEMStack(&parser->sem_stack);
    switch (m1.type) {
        case MT_VAR:
            codeKABx(&parser->c_state, OP_LOAD, K_NULL, R0, m1.value.p);
            break;
        case MT_T:
            codeKABx(&parser->c_state, OP_MOVS, K_NULL, R0, 0);
            break;
        case MT_OBJ_P:
            codeKABx(&parser->c_state, OP_LOAD_P, K_NULL, R0, 0);
            break;
        default:
            throwCoder(parser, SEM_TYPE_ERROR);
            return SEM_ERROR;
    }
    switch (m2.type) {
        case MT_VAR:
            codeKABx(&parser->c_state, OP_LOAD, K_NULL, R1, m2.value.p);
            break;
        case MT_T:
            codeKABx(&parser->c_state, OP_MOVS, K_NULL, R1, 0);
            break;
        case MT_OBJ_P:
            codeKABx(&parser->c_state, OP_LOAD_P, K_NULL, R1, 0);
            break;
        default:
            throwCoder(parser, SEM_TYPE_ERROR);
            return SEM_ERROR;
    }
    codeOPK(&parser->c_state, OP_IMUL, K_NULL);
    m1.type = MT_T;
    pushSEMStack(&parser->sem_stack, m1);
    return SEM_OK;
}

static int acSemPushWhile(Parser *parser) {
    LoopEvn *pre = parser->loop_evn;
    parser->loop_evn = malloc(sizeof(LoopEvn));
    parser->loop_evn->pre = pre;
    MInfo item;
    item.type = MT_WP;
    item.value.p = parser->c_state.is_declare_func ? parser->c_state.vm_i_f_p : parser->c_state.vm_i_p;
    pushSEMStack(&parser->sem_stack, item);
    return SEM_OK;
}

static int acIfJudge(Parser *parser) {
    MInfo m = popSEMStack(&parser->sem_stack);
    genCodeByMInfo(parser, m, R0);
    m.type = MT_IP;
    m.value.p = parser->c_state.is_declare_func ? parser->c_state.vm_i_f_p : parser->c_state.vm_i_p;
    pushSEMStack(&parser->sem_stack_if, m);
    codeOPK(&parser->c_state, OP_CJUMP, K_NULL);
    return SEM_OK;
}

static int acWhileJudge(Parser *parser) {
    MInfo m = popSEMStack(&parser->sem_stack);
    genCodeByMInfo(parser, m, R0);
    m.type = MT_IP;
    m.value.p = parser->c_state.is_declare_func ? parser->c_state.vm_i_f_p : parser->c_state.vm_i_p;
    pushSEMStack(&parser->sem_stack, m);
    codeOPK(&parser->c_state, OP_CJUMP, K_NULL);
    return SEM_OK;
}

static int acWhileEnd(Parser *parser) {
    MInfo m = popSEMStack(&parser->sem_stack);
    Uint ip = parser->c_state.is_declare_func ? parser->c_state.vm_i_f_p : parser->c_state.vm_i_p;
    while (m.type == MT_IP) {
        SET_ARG_Bx(parser->c_state.memory->VM_I[m.value.p], (ip - m.value.p));
        m = popSEMStack(&parser->sem_stack);
    }
    codeKABx(&parser->c_state, OP_JUMP, JUMP_R, 0, ip + 1 - m.value.p);
    LoopEvn *t = parser->loop_evn;
    parser->loop_evn = parser->loop_evn->pre;
    free(t);
    return SEM_OK;
}

static int acWhileBreak(Parser *parser) {
    if (!parser->loop_evn) {
        throwCoder(parser, SEM_BREAK_NOT_IN_LOOP_STRUCT_ERROR);
        return SEM_BREAK_NOT_IN_LOOP_STRUCT_ERROR;
    }
    MInfo item;
    item.type = MT_IP;
    item.value.p = parser->c_state.is_declare_func ? parser->c_state.vm_i_f_p : parser->c_state.vm_i_p;
    pushSEMStack(&parser->sem_stack, item);
    codeOPK(&parser->c_state, OP_JUMP, JUMP_F);
    return SEM_OK;
}

static int acIfEnd(Parser *parser) {
    MInfo m = popSEMStack(&parser->sem_stack_if);
    CState *c_state = &parser->c_state;
    SET_ARG_Bx(c_state->memory->VM_I[m.value.p],
               ((c_state->is_declare_func ? c_state->vm_i_f_p : c_state->vm_i_p) - m.value.p - 1));
    return SEM_OK;
}

static int acSemPushElse(Parser *parser) {
    MInfo item;
    item.type = MT_IP;
    item.value.p = parser->c_state.is_declare_func ? parser->c_state.vm_i_f_p : parser->c_state.vm_i_p;
    pushSEMStack(&parser->sem_stack_if, item);
    codeOPK(&parser->c_state, OP_JUMP, K_NULL);
    return SEM_OK;
}

static int acElseEnd(Parser *parser) {
    CState *c_state = &parser->c_state;
    MInfo m = popSEMStack(&parser->sem_stack_if);
    Uint p = m.value.p;
    SET_ARG_Bx(c_state->memory->VM_I[p],
               ((c_state->is_declare_func ? c_state->vm_i_f_p : c_state->vm_i_p) - p - 1));
    m = popSEMStack(&parser->sem_stack_if);
    SET_ARG_Bx(c_state->memory->VM_I[m.value.p], (p - m.value.p));
    return SEM_OK;
}

static int acDefFuncStart(Parser *parser) {
    if (parser->c_state.is_declare_func) {
        throwCoder(parser, SEM_FUNC_CAN_NOT_DEFINE_IN_FUNC);
        return SEM_FUNC_CAN_NOT_DEFINE_IN_FUNC;
    }
    parser->c_state.is_declare_func = True;
    FuncHashNode *node;
    if (lookUpFuncHashMap(&parser->symbols.func_table, parser->current_token.token_value.string->data, &node)) {
        throwCoder(parser, SEM_REDEFINED_FUNC_ERROR);
        return SEM_REDEFINED_FUNC_ERROR;
    }
    node = insertFuncHashMap(&parser->symbols.func_table, parser->current_token.token_value.string->data, 0, 0,
                             parser->c_state.vm_i_f_p);
    if (parser->lexer->y_state->mode == YSTATE_INTERACTIVE) {
        stageFunc(parser);
    }
    parser->func_info = &node->value;
    parser->c_state.func_mem_p = 0;
    clearVarHashMap(&parser->symbols.inner_var_table);
    return SEM_OK;
}

static int acDefCountParams(Parser *parser) {
    parser->func_info->func_params++;
    Uint p;
    if (findVar(&parser->symbols.inner_var_table, parser->current_token.token_value.string->data, &p)) {
        throwCoder(parser, SEM_REDECLARE_VAR_ERROR);
        return SEM_REDECLARE_VAR_ERROR;
    } else {
        insertVarHashMap(&parser->symbols.inner_var_table, parser->current_token.token_value.string->data,
                         parser->c_state.func_mem_p++);
    }
    return SEM_OK;
}

static int acReturn(Parser *parser) {
    if (!parser->c_state.is_declare_func) {
        return SEM_RETURN_NOT_IN_FUNC;
    }
    if (isEmptySEMStack(&parser->sem_stack)) {
        codeKABC(&parser->c_state, OP_MOV, K_NULL, 0, R3, R7);
    } else {
        MInfo m = popSEMStack(&parser->sem_stack);
        genCodeByMInfo(parser, m, R3);
    }
    codeOPK(&parser->c_state, OP_LEV, K_NULL);
    return SEM_OK;
}

static int acDefFuncEnd(Parser *parser) {
    codeOPK(&parser->c_state, OP_LEV, K_NULL);
    parser->c_state.is_declare_func = False;
    return SEM_OK;
}

static int acMatCountRow(Parser *parser) {
    if (parser->mat_state.t_col > parser->mat_state.col)
        parser->mat_state.col = parser->mat_state.t_col;
    parser->mat_state.t_col = 0;
    ++parser->mat_state.row;
    codeKABx(&parser->c_state, OP_INC, K_NULL, 0, 0);
    return SEM_OK;
}

static int acMatCountCol(Parser *parser) {
    MInfo item = popSEMStack(&parser->sem_stack);
    genCodeByMInfo(parser, item, R4);
    codeKABx(&parser->c_state, OP_MOV, MOV_MATV, 0, 0);
    parser->mat_state.t_col++;
    return SEM_OK;
}

static int acMatStart(Parser *parser) {
    memset(&parser->mat_state, 0, sizeof(MatState));
    parser->mat_state.i_p = parser->c_state.is_declare_func ? parser->c_state.vm_i_f_p : parser->c_state.vm_i_p;
    codeKABx(&parser->c_state, OP_LOAD_CONST, LOAD_CONST_BOOL, R0, 0);
    codeKABx(&parser->c_state, OP_LOAD_CONST, LOAD_CONST_BOOL, R1, 0);
    codeKABx(&parser->c_state, OP_MALLOC, MALLOC_MAT, R2, 0);
    return SEM_OK;
}

static int acMatEnd(Parser *parser) {
    CState *c_state = &parser->c_state;
    SET_ARG_B(c_state->memory->VM_I[parser->mat_state.i_p], parser->mat_state.row);
    SET_ARG_B(c_state->memory->VM_I[parser->mat_state.i_p + 1], parser->mat_state.col);
    MInfo item = popSEMStack(&parser->sem_stack);
    codeKABx(c_state, OP_STORE, K_NULL, R2, item.value.p);
    return SEM_OK;
}

static int acMatIndex(Parser *parser) {
    MInfo m2 = popSEMStack(&parser->sem_stack), m1 = popSEMStack(&parser->sem_stack);

    switch (m2.type) {
        case MT_VAR:
            codeKABx(&parser->c_state, OP_LOAD, K_NULL, R0, m2.value.p);
            break;
        case MT_T:
            codeKABx(&parser->c_state, OP_MOVS, K_NULL, R0, 0);
            break;
        case MT_INT_CONST:
            codeKABx(&parser->c_state, OP_LOAD_CONST, LOAD_CONST_INT, R0, getIntConstP(parser, m2.value.i));
            break;
        default:
            throwCoder(parser, SEM_TYPE_ERROR);
            return SEM_TYPE_ERROR;
    }
    codeKABx(&parser->c_state, OP_PUSH, K_NULL, R0, 0);
    switch (m1.type) {
        case MT_VAR:
            codeKABx(&parser->c_state, OP_LOAD, K_NULL, R0, m1.value.p);
            break;
        case MT_T:
            codeKABx(&parser->c_state, OP_MOVS, K_NULL, R0, 0);
            break;
        case MT_INT_CONST:
            codeKABx(&parser->c_state, OP_LOAD_CONST, LOAD_CONST_INT, R0, getIntConstP(parser, m1.value.i));
            break;
        default:
            throwCoder(parser, SEM_TYPE_ERROR);
            return SEM_TYPE_ERROR;
    }
    codeKABx(&parser->c_state, OP_PUSH, K_NULL, R0, 0);
    MInfo item = popSEMStack(&parser->sem_stack);
    codeKABx(&parser->c_state, OP_MAT_INDEX, K_NULL, 0, item.value.p);
    item.type = MT_MAT_V;
    pushSEMStack(&parser->sem_stack, item);
    return SEM_OK;
}

static int acIndex(Parser *parser) {
    MInfo m2 = popSEMStack(&parser->sem_stack);
    genCodeByMInfo(parser, m2, R1);
    MInfo m1 = popSEMStack(&parser->sem_stack);
    genCodeByMInfo(parser, m1, R0);
    codeKABC(&parser->c_state, OP_INDEX, K_NULL, 0, R0, R1);
    m1.type = MT_OBJ_P;
    pushSEMStack(&parser->sem_stack, m1);
    return SEM_OK;
}

static int acArrayStart(Parser *parser) {
    MInfo item = popSEMStack(&parser->sem_stack);
    codeKABx(&parser->c_state, OP_MALLOC, MALLOC_LIST, R1, item.value.p + 1);
    codeKABx(&parser->c_state, OP_STORE, K_NULL, R1, item.value.p);
    parser->c_state.array_start = item.value.p + 1;
    parser->c_state.array_offset = 0;
    parser->c_state.is_declare_array_length = False;
    return SEM_OK;
}

static int acArrayValueAssign(Parser *parser) {
    MInfo m2 = popSEMStack(&parser->sem_stack);
    genCodeByMInfo(parser, m2, R1);
    if (parser->c_state.is_declare_array_length && parser->c_state.array_offset >= parser->c_state.array_length) {
        throwCoder(parser, SEM_ARRAY_LENGTH_ERROR);
        return SEM_ARRAY_LENGTH_ERROR;
    }
    codeKABx(&parser->c_state, OP_STORE, K_NULL, R1, parser->c_state.array_start + parser->c_state.array_offset++);

    return SEM_OK;
}

static int acArrayEnd(Parser *parser) {
    codeKABC(&parser->c_state, OP_MOV, MOV_T, 0, R1, 0);
    codeKABx(&parser->c_state, OP_STORE, K_NULL, R1, parser->c_state.array_start +
                                                     (parser->c_state.is_declare_array_length
                                                      ? parser->c_state.array_length : parser->c_state.array_offset++));
    if (parser->c_state.is_declare_array_length) {
        parser->c_state.array_offset = parser->c_state.array_length + 1;
    }
    if (parser->c_state.is_declare_func) {
        parser->func_info->var_nums += parser->c_state.array_offset, parser->c_state.func_mem_p += parser->c_state.array_offset;
    } else {
        parser->c_state.vm_mem_p += parser->c_state.array_offset;
    }
    return SEM_OK;
}

static int acSetArrayLength(Parser *parser) {
    parser->c_state.is_declare_array_length = True;
    MInfo item = popSEMStack(&parser->sem_stack);
    parser->c_state.array_length = item.value.i;
    return SEM_OK;
}